package com.yr.ryjk.pay.service;

import java.io.OutputStream;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import com.unionpay.acp.UnionPayAppConsume;
import com.yr.ryjk.coin.dao.CoinRecordMapper;
import com.yr.ryjk.coin.entity.CoinRecord;
import com.yr.ryjk.common.Constant;
import com.yr.ryjk.common.ErrorType;
import com.yr.ryjk.common.Pagination;
import com.yr.ryjk.doctor.dao.DoctorMapper;
import com.yr.ryjk.doctor.entity.Doctor;
import com.yr.ryjk.jpush.JpushMessage;
import com.yr.ryjk.jpush.JpushSendService;
import com.yr.ryjk.param.dao.ParamMapper;
import com.yr.ryjk.param.entity.Key;
import com.yr.ryjk.param.entity.Param;
import com.yr.ryjk.pay.ExcelCash;
import com.yr.ryjk.pay.ExcelGenerator;
import com.yr.ryjk.pay.dao.BankCardMapper;
import com.yr.ryjk.pay.dao.CashInMapper;
import com.yr.ryjk.pay.dao.CashOutMapper;
import com.yr.ryjk.pay.entity.BankCard;
import com.yr.ryjk.pay.entity.CashIn;
import com.yr.ryjk.pay.entity.CashOut;
import com.yr.ryjk.pay.vo.CashInUserVO;
import com.yr.ryjk.pay.vo.CashOutDoctorVO;
import com.yr.ryjk.pay.vo.CashOutVO;
import com.yr.ryjk.redis.JedisUtil;
import com.yr.ryjk.user.dao.UserMapper;
import com.yr.ryjk.user.entity.User;
import com.yr.ryjk.util.IDGenerator;
import com.yr.ryjk.util.JSONUtil;

@Service
public class PayService implements IPayService{
	@Autowired
	private BankCardMapper bankCardMapper;
	@Autowired
	private DoctorMapper doctorMapper;
	@Autowired
	private UserMapper userMapper;
	@Autowired
	private CashOutMapper cashOutMapper;
	@Autowired
	private CashInMapper cashInMapper;
	@Autowired
	private ParamMapper paramMapper;
	@Autowired
	private CoinRecordMapper coinRecordMapper;

	@Override
	public List<BankCard> getAllCardOfDoc(String token) {
		String phone=JedisUtil.getPhoneByToken(token);
		return bankCardMapper.selectByDocPhone(phone);
	}

	@Override
	public Map<String, Object> addCardToDoctor(Integer dId, String openBank,
			String cardNo, String token) {
		//1.验证银行卡是否已存在
		BankCard bankCard=bankCardMapper.selectByCardNo(cardNo);
		if(bankCard!=null){
			return JSONUtil.getJSON(ErrorType.BANK_CARD_EXISTS_ERROR);
		}
		//2.获取医生信息
		String phone=JedisUtil.getPhoneByToken(token);
		Doctor doctor=doctorMapper.selectByPhone(phone);
		
		//3.插入银行卡信息
		BankCard card=new BankCard();
		card.setCardId(IDGenerator.gen32UUID());
		card.setAddTime(new Date());
		card.setCardNo(cardNo);
		card.setOpenBank(openBank);
		card.setdId(dId);
		card.setDocId(doctor.getId());
		bankCardMapper.insert(card);
		
		return JSONUtil.getJSON(ErrorType.SUCCESS);
	}

	@Override
	public void deleteCard(String cardId, String token) {
		String phone=JedisUtil.getPhoneByToken(token);
		bankCardMapper.deleteByIdAndDocPhone(cardId,phone);
	}

	@Override
	public Map<String, Object> addCashOut(String cardId, int coinAmount, String token) {
		//1.验证健康币是否足够,避免接口被攻击
		String phone=JedisUtil.getPhoneByToken(token);
		Doctor doctor=doctorMapper.selectByPhone(phone);
		if(doctor==null){
			return JSONUtil.getJSON(ErrorType.TOKEN_ERROR);
		}
		if(doctor.getCoin()<coinAmount){
			return JSONUtil.getJSON(ErrorType.COIN_NOT_ENOUGH_ERROR);
		}
		
		//2.验证健康币md5
		if(!DigestUtils.md5DigestAsHex((doctor.getCoin()+Constant.COIN_MD5_SECRET_KEY).getBytes()).equals(doctor.getCoinMd5())){
			return JSONUtil.getJSON(ErrorType.COIN_MD5_CHECK_ERROR);
		}
		
		//3.扣除账户中的健康币
		int newCoin=doctor.getCoin()-coinAmount;
		String coinMd5=DigestUtils.md5DigestAsHex((newCoin+Constant.COIN_MD5_SECRET_KEY).getBytes());
		doctorMapper.updateCoinById(newCoin, coinMd5, doctor.getTotalGainCoin()+doctor.getAskPrice(), doctor.getId());
		
		//4.新增提现记录
		CashOut c=new CashOut();
		c.setId(IDGenerator.gen32UUID());
		c.setCardId(cardId);
		c.setCoinAmount(coinAmount); 		//冻结健康币数量
		c.setDocId(doctor.getId());
		c.setOperateTime(new Date());
		c.setStatus(0);
		
		cashOutMapper.insert(c);
		return JSONUtil.getJSON(ErrorType.SUCCESS);
	}

	@Override
	public Map<String, Object> listCashOut(int pageNo, int pageSize, String token) {
		String phone=JedisUtil.getPhoneByToken(token);
		Doctor doctor=doctorMapper.selectByPhone(phone);
		if(doctor==null){
			return JSONUtil.getJSON(ErrorType.TOKEN_ERROR);
		}
		List<CashOutVO> list=cashOutMapper.selectCashOutVoOfPageAndDoc((pageNo-1)*pageSize,pageSize,doctor.getId());
		int count=cashOutMapper.selectCountAndDoc(doctor.getId());
		
		Map<String, Object> map=new HashMap<String, Object>();
		map.put("list", list);
		map.put("pagination", new Pagination(pageSize, pageNo, count));
		return JSONUtil.getJSON(ErrorType.SUCCESS,map);
	}
	
	@Override
	public Map<String, Object> submitOrder(int type, int amount, String token) throws ParseException {
		String phone=JedisUtil.getPhoneByToken(token);
		User user=userMapper.selectUserByPhone(phone);
		if(user==null){
			return JSONUtil.getJSON(ErrorType.TOKEN_ERROR);
		}
		
		if(type==0){            //支付宝
			//TODO 支付宝对接
		}else if(type==1){      //银联
			//1.对接获取tn码
			Map<String, String> map=UnionPayAppConsume.exec(amount);
			if(UnionPayAppConsume.isSuccess(map)){  		   //对接成功
				//2.本地保存充值记录
				String tn=UnionPayAppConsume.getTnCode(map);
				CashIn in=new CashIn();
				in.setId(IDGenerator.gen32UUID());
				in.setInType(type);
				in.setCashAmount(amount);
				in.setCoinAmount(amount/10);//10分钱一个健康币
				in.setTn(tn);
				in.setOrderNo(map.get("orderId"));
				in.setInTime(UnionPayAppConsume.getTxnTime(map));
				in.setStatus(0);   //尚未支付成功
				in.setUserId(user.getId());
				
				cashInMapper.insert(in);
				
				//TODO 3.开启轮询请求,定时查询定的支付状态,避免因银联发送不到acceptResult接口而造成钱扣掉而健康币不加上的问题
				return JSONUtil.getJSON(ErrorType.SUCCESS,tn);
			}else {
				return JSONUtil.getJSON(ErrorType.UNIONPAY_MATCH_ERROR);
			}
		}
		return JSONUtil.getJSON(ErrorType.PAY_TYPE_ERROR);
	}

	@Override
	public void updateCoinInFinishByTn(Date txnTime,int txnAmt,String orderId) {
		//1.添加健康币
		CashIn in=cashInMapper.selectByOrderNo(orderId);
		if(in.getStatus()==1){
			Logger.getLogger(this.getClass()).error("充值错误：银联多次返回异步通知，订单号为"+orderId+",金额为"+txnAmt);
			return;
		}
		if(txnAmt>in.getCashAmount()){
			Logger.getLogger(this.getClass()).error("充值错误：充值数量不匹配，在接受银联返回信息中，显示充值"+txnAmt+"分；本地服务器中显示充值"+in.getCashAmount()+"分");
			return;
		}
		User user=userMapper.selectByPrimaryKey(in.getUserId());
		int coin=user.getCoin()+txnAmt;
		
		userMapper.updateCoinById(coin, DigestUtils.md5DigestAsHex((coin+Constant.COIN_MD5_SECRET_KEY).getBytes()), user.getId());
		//2.更新状态
		cashInMapper.updateStatusByOrderId(orderId);
		
		//3.健康币操作记录
		CoinRecord record=new CoinRecord();
		record.setCoinRecordId(IDGenerator.gen32UUID());
		record.setUserId(user.getId());
		record.setOperateTime(txnTime);
		record.setCount(txnAmt);
		record.setType(3);
		record.setContent("充值了"+in.getCoinAmount()+"个健康币");
		coinRecordMapper.insert(record);
		
		//4.推送消息
		final String phone=user.getPhone();
		final int count=txnAmt;
		new Thread(new Runnable() {
			@Override
			public void run() {
				String jpDevice  = JedisUtil.getJPushKeyByPhone(phone);
				JpushMessage msg = new JpushMessage();
				msg.setTitle("瑞翼健康");
				msg.setContent("充值成功,共充值"+count+"个健康币");
				JpushSendService.sendAndroidNotice(msg, new HashMap<String, String>(), new String[]{jpDevice});
			}
		}).start();
	}
	
	@Override
	public Map<String, Object> getListOfPage(int pageNo, int pageSize,int status,String name,String phone) {
		List<CashOutDoctorVO> list=cashOutMapper.selectCashOut((pageNo-1)*pageSize,pageSize, status,name,phone);
		int count=cashOutMapper.selectCount(status,name,phone);
		
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("list", list);
		map.put("pagination", new Pagination(pageSize, pageNo, count));
		return map;
	}
	
	@Override
	public void updateSolveCashout(String ids) {
		//1.更新状态
		cashOutMapper.updateSolveCashOutByIds(ids);
		
		List<CashOutDoctorVO> list= cashOutMapper.selectByIds(ids);
		for(CashOutDoctorVO cashout:list){
			//2.健康币收支记录
			CoinRecord cr=new CoinRecord();
			cr.setCoinRecordId(IDGenerator.gen32UUID());
			cr.setType(2);
			cr.setUserId(cashout.getDocId());
			cr.setCount(cashout.getCoinAmount());
			cr.setContent("提现扣除"+cashout.getCoinAmount()+"个健康币");
			cr.setOperateTime(cashout.getOperateTime());
			coinRecordMapper.insert(cr);
			
			//3.极光 --通知,通知医生提现成功
        	final String phone = cashout.getPhone();  
        	final int coinAmont = cashout.getCoinAmount();
        	new Thread(new Runnable() {
				@Override
				public void run() {
		     		String jpDevice  = JedisUtil.getJPushKeyByPhone(phone);
		     		JpushMessage msg = new JpushMessage();
		     		msg.setTitle("瑞翼健康");
		     		msg.setContent("提现成功"+coinAmont+"个健康币");
		     		JpushSendService.sendAndroidNotice(msg, new HashMap<String, String>(), new String[]{jpDevice});	
				}
			}).start();
        } 
	}
	@Override
	public CashOutDoctorVO getByPrimaryKey(String id) {
		return cashOutMapper.selectCashById(id);
	}

	@Override
	public void exportExcel(int status,OutputStream os) throws Exception {
		List<CashOutDoctorVO> list=cashOutMapper.selectVoByStatus(status);
		new ExcelGenerator().genExcelStream(list,os);
	}

	@Override
	public String getCashOutTip() {
		Param param=paramMapper.selectByPrimaryKey(Key.cashout_receive_time_tip.getKey());
		return param.getValue();
	}
	@Override
	public Map<String, Object> getListOfCashInPage(int pageNo, int pageSize,
			Date inTime, String name, String phone) {
		List<CashInUserVO> list=cashInMapper.selectCashInOfPageAndUser((pageNo-1)*pageSize,pageSize,inTime,name,phone);
		int count=cashInMapper.selectCountAndUser(inTime,name,phone);
		
		Map<String, Object> map=new HashMap<String, Object>();
		map.put("list", list);
		map.put("pagination", new Pagination(pageSize, pageNo, count));
		return map;
	}

	@Override
	public Map<String, Object> getCashInRecordByPrimaryKey(int pageNo, int pageSize,String userId) {
		List<CashIn> list=cashInMapper.selectCashInByUserId((pageNo-1)*pageSize,pageSize,userId);
		int count=cashInMapper.selectCountByUserId(userId);
		
		Map<String, Object> map=new HashMap<String, Object>();
		map.put("list", list);
		map.put("pagination", new Pagination(pageSize, pageNo, count));
		return map;
	}

	@Override
	public void exportCashInExcel(String userId, OutputStream os) throws Exception {
		List<CashInUserVO> list=cashInMapper.selectVoByUserId(userId);
		new ExcelCash().genExcelStream(list,os);
	}
}